package com.moyun.common.utils;

import com.moyun.model.po.system.SysUserEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.stereotype.Component;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * <h3>moyun-base</h3>
 * <p>基于内存的Session工具类</p>
 *
 * @author : ybx
 * @date : 2021-09-02 15:23:34
 **/
@RequiredArgsConstructor
@Component
public class MemorySessionUtil {
    /**
     * SessionRegistry Session会话注册表
     * PersistentTokenRepository 持久令牌的Dao层 对应persistent_logins表 封装了基本的增删改操作
     */
    private final SessionRegistry sessionRegistry;
    private final PersistentTokenRepository persistentTokenRepository;

    /*    remember-me相关操作     */


    /**
     * 清除remember-me持久化tokens
     */
    public void rememberMeRemoveUserTokens(String userName) {
        persistentTokenRepository.removeUserTokens(userName);
    }

    /**
     * 获取 "remember-me" cookie
     */
    public static Cookie getRememberMeCookie(HttpServletRequest request) {
        for (Cookie cookie : request.getCookies()) {
            if (cookie.getName().equals("remember-me")) {
                return cookie;
            }
        }
        return null;
    }

    /*  SessionRegistry相关操作  */


    /**
     * 根据sessionId从sessionRegistry获取用户
     */
    public SysUserEntity sessionRegistryGetUserBySessionId(String sessionId) {
        SessionInformation sessionInformation = sessionRegistry.getSessionInformation(sessionId);
        if (sessionInformation != null) {
            return (SysUserEntity) sessionInformation.getPrincipal();
        }
        return null;
    }

    /**
     * 从sessionRegistry中删除user
     */
    public void sessionRegistryRemoveUser(User user) {
        //1、清除remember-me持久化tokens
        this.rememberMeRemoveUserTokens(user.getUsername());

        List<SessionInformation> allSessions = this.getSessionInformationListFromSessionRegistry(user);
        if (allSessions != null) {
            for (SessionInformation sessionInformation : allSessions) {
                sessionInformation.expireNow();
                sessionRegistry.removeSessionInformation(sessionInformation.getSessionId());
            }

            //清除当前的上下文
            SecurityContextHolder.clearContext();

        }
    }

    /**
     * 指定loginName从sessionRegistry中删除user
     * 当需要使某个用户强制下线时,调用此方法即可
     */
    public boolean sessionRegistryRemoveUserByLoginName(String loginName) {
        boolean flag = false;
        //1、首先清除remember-me持久化tokens
        this.rememberMeRemoveUserTokens(loginName);

        //2、获取会话表中记录的所有用户
        // 注意--->我们这里只需要将 指定用户对应的所有SessionInformation对象中的expired属性标记为true即可
        // 坑--->如果我们是从 SessionRegistry会话注册表中 移除了 指定用户的 Session信息.如sessionRegistry.removeSessionInformation(sessionInformation.getSessionId());
        // 但 ConcurrentSessionFilter中并没有对SessionInformation==null的相关操作
        // 而且 SecurityContextHolder.getContext()依然保存着 指定用户的认证信息 这样会造成指定用户没有重新登录但依然可以访问系统
        List<Object> allPrincipals = getAllPrincipalsFromSessionRegistry();
        for (Object principal : allPrincipals) {
            // 这里用接口来接受实现类,是一定不会出错的
            UserDetails user = (UserDetails) principal;
            // 判断会话表中记录的用户名和参数用户名
            if (user.getUsername().equals(loginName)) {
                List<SessionInformation> allSessions = sessionRegistry.getAllSessions(user, true);
                if (allSessions != null) {
                    for (SessionInformation sessionInformation : allSessions) {
                        // 让 session 立刻失效
                        sessionInformation.expireNow();
//                        sessionRegistry.removeSessionInformation(sessionInformation.getSessionId());
                    }
                    flag = true;
                }
                break;
            }
        }
        return flag;

    }

    /**
     * 向sessionRegistry注册user
     */
    public void sessionRegistryAddUser(String sessionId, Object user) {
        sessionRegistry.registerNewSession(sessionId, user);
    }

    /**
     * 根据user从sessionRegistry获取SessionInformation
     * User 是UserDetails接口的实现类
     */
    public List<SessionInformation> getSessionInformationListFromSessionRegistry(User user) {
        return sessionRegistry.getAllSessions(user, true);
    }

    /**
     * 从sessionRegistry获取 所有注册的用户
     * User 是UserDetails接口的实现类
     */
    public List<Object> getAllPrincipalsFromSessionRegistry() {
        return sessionRegistry.getAllPrincipals();

    }

}
